package voloshyn.paliy.ui;

import voloshyn.paliy.arduino.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class JoystickView extends View {
    private static final String TAG = JoystickView.class.getName();
    private static final int KNOB_MOVE_RADIUS = 60;
    private static final int KNOB_RADIUS = 40;
    private Bitmap background, knob;
    private boolean isActive = false;
    private Point touchDownPoint = new Point();
    private Rect knobPosition = new Rect();
    private int deltaX, deltaY;

    public JoystickView(Context context, AttributeSet attrs) {
	super(context, attrs);
	knob = BitmapFactory.decodeResource(context.getResources(),
		R.drawable.onscreen_control_knob);
	background = BitmapFactory.decodeResource(context.getResources(),
		R.drawable.onscreen_control_base);
	initKnobDefaultPosition();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
	setMeasuredDimension(background.getWidth(), background.getHeight());
    }

    @Override
    protected void onDraw(Canvas canvas) {
	super.onDraw(canvas);
	canvas.drawBitmap(background, 0, 0, null);
	canvas.drawBitmap(knob, null, knobPosition, null);
    }

    private void initKnobDefaultPosition() {
	knobPosition.left = background.getWidth() / 2 - knob.getWidth() / 2;
	knobPosition.top = background.getHeight() / 2 - knob.getHeight() / 2;
	knobPosition.right = knobPosition.left + knob.getWidth();
	knobPosition.bottom = knobPosition.top + knob.getHeight();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
	if(!isEnabled())
	{
	    return true;
	}
	int action = event.getAction();
	switch (action) {
	case MotionEvent.ACTION_DOWN: {
	    // if(knobPosition.contains((int)event.getX(), (int)event.getY()))
	    // {
	    // Log.v(TAG, "[onTouchEvent] ACTION_DOWN");
	    // }
	    if (getDistanceFromCentr(event.getX(), event.getY()) < KNOB_RADIUS) {
		isActive = true;
		touchDownPoint.x = (int) event.getX();
		touchDownPoint.y = (int) event.getY();
		deltaX = (int) (event.getX() - knobPosition.left);
		deltaY = (int) (event.getY() - knobPosition.top);
		// Log.v(TAG, "[onTouchEvent] ACTION_DOWN ");
	    }
	    break;
	}
	case MotionEvent.ACTION_MOVE: {
	    if (isActive) {

		// Log.v(TAG, "[onTouchEvent] ACTION_MOVE ");
		int savedWidht = knobPosition.width();
		int savedHeight = knobPosition.height();
		knobPosition.left = (int) event.getX() - deltaX;
		knobPosition.top = (int) event.getY() - deltaY;
		knobPosition.right = knobPosition.left + savedWidht;
		knobPosition.bottom = knobPosition.top + savedHeight;
		if (getDistanceFromCentr(knobPosition.centerX(),
			knobPosition.centerY()) > KNOB_MOVE_RADIUS) {
		    double angle = Math.atan2(knobPosition.centerY()
			    - getHeight() / 2, knobPosition.centerX()
			    - getWidth() / 2);
		    if (angle >= 0) {
			angle = 2 * Math.PI - angle;
		    }
		    angle = Math.abs(angle);
		    double xCentrNew = KNOB_MOVE_RADIUS * Math.cos(angle)
			    + getWidth() / 2;
		    double yCentrNew = getHeight()
			    - (KNOB_MOVE_RADIUS * Math.sin(angle) + getHeight() / 2);
		    knobPosition.left = (int) (xCentrNew - knob.getWidth() / 2);
		    knobPosition.top = (int) (yCentrNew - knob.getHeight() / 2);
		    knobPosition.right = (int) (xCentrNew + knob.getWidth() / 2);
		    knobPosition.bottom = (int) (yCentrNew + knob.getHeight() / 2);
		    // Log.v(TAG, "xCentrNew:" + xCentrNew + " yCentrNew:"
		    // + yCentrNew+" angle:"+angle);

		}
		invalidate();
	    }
	    break;
	}
	default: {
	    // Log.v(TAG, "[onTouchEvent] default ");
	    initKnobDefaultPosition();
	    isActive = false;
	    invalidate();
	}
	}
	return true;
    }

    private double getDistanceFromCentr(float theX, float theY) {
	float centrX = getWidth() / 2;
	float centrY = getHeight() / 2;
	return Math.sqrt((centrX - theX) * (centrX - theX) + (centrY - theY)
		* (centrY - theY));
    }

    public void setOnJoystickListener(
	    final OnJoystickListener theJoystickListener, final int timeUpdate) {
	CountDownTimer downTimer = new CountDownTimer(timeUpdate, 10) {

	    @Override
	    public void onTick(long millisUntilFinished) {

	    }

	    @Override
	    public void onFinish() {
		if (isActive) {
		    theJoystickListener.onJoystickPosition(
			    knobPosition.centerX() - getWidth() / 2,
			    -(knobPosition.centerY() - getHeight() / 2));
		}
		setOnJoystickListener(theJoystickListener, timeUpdate);
	    }
	};
	downTimer.start();
    }
}
